package com.yourenbang.lingyun.transaction.web.service.impl.yxy;

import com.alibaba.fastjson.JSONObject;
import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.enums.ChannelIdEnums;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.pay.PayFromEnum;
import com.yourenbang.lingyun.constants.enums.pay.PayTypeEnum;
import com.yourenbang.lingyun.constants.enums.table.MerchantEnum;
import com.yourenbang.lingyun.constants.enums.table.PayTransactionEnum;
import com.yourenbang.lingyun.core.base.bean.SpringContextUtils;
import com.yourenbang.lingyun.core.message.Result;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.core.util.StringUtils;
import com.yourenbang.lingyun.core.util.date.DateFormat;
import com.yourenbang.lingyun.core.util.date.LocalDateUtils;
import com.yourenbang.lingyun.domain.Merchant21;
import com.yourenbang.lingyun.domain.Terminal;
import com.yourenbang.lingyun.domain.Terminal21;
import com.yourenbang.lingyun.mapper.Merchant21Mapper;
import com.yourenbang.lingyun.mapper.UserBaseMapper;
import com.yourenbang.lingyun.transaction.constant.LklTransTypeEnum;
import com.yourenbang.lingyun.transaction.web.domain.dto.yxy.YsTradeDTO;
import com.yourenbang.lingyun.transaction.web.service.CommonService;
import com.yourenbang.lingyun.transaction.web.service.pay.klks.PayEposService;
import com.yourenbang.lingyun.transaction.web.service.yxy.YishengTradeService;
import com.yourenbang.lingyun.transaction.web.service.yxy.YxyTradeService;
import com.yourenbang.merchant.api.model.dto.CheckActiveRewardYxyDTO;
import com.yourenbang.merchant.api.model.dto.SaveMerchantDTO;
import com.yourenbang.merchant.api.model.dto.YsPaySaveMerchantDTO;
import com.yourenbang.merchant.api.service.yxy.MerchantYxyApiService;
import com.yourenbang.merchant.api.service.yxy.MerchantYxyRewardApiService;
import com.yourenbang.terminal.api.model.dto.RpcYxyCallbackBindDTO;
import com.yourenbang.terminal.api.service.RpcYxyTerminalService;
import com.yourenbang.transaction.api.model.vo.pay.PayTransaction;
import com.yourenbang.transaction.api.service.pay.PayTypeApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;

/**
 * @Description
 * @Date 2021/4/26 15:13
 * @Created by Jason
 */
@Slf4j
@Service
public class YishengTradeServiceImpl implements YishengTradeService {

    @Autowired
    MerchantYxyApiService merchantYxyApiService;

    @Autowired
    RpcYxyTerminalService rpcYxyTerminalService;

    @Autowired
    Merchant21Mapper merchant21Mapper;

    @Autowired
    private MerchantYxyRewardApiService merchantYxyRewardApiService;

    @Autowired
    private PayEposService payEposService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private YxyTradeService yxyTradeService;

    @Autowired
    private PayTypeApiService payTypeApiService;
    /**
     * 商户通知
     *
     * @param jsonObject
     * @return
     */
    @Override
    public Result merchantNotify(JSONObject jsonObject) {

        log.info("易生商户通知");
        if (commonService.repeatSubmit("callbackYisheng-merchantNotify:" + jsonObject.getString("shopNo"))) {
            log.info("重复推送跳过:{}", jsonObject.toJSONString());
            return Result.builder().fail(BizCodeMessages.VALIDATOR_REPEAT_SUBMIT, "重复请求");
        }
        String merchantNo = jsonObject.getString("shopNo");
        Merchant21 merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(merchantNo);
        if (Objects.isNull(merchant21)) {
            SaveMerchantDTO dto = new SaveMerchantDTO();
            dto.setMerchantNo(merchantNo);
            dto.setAgentNo(jsonObject.getString("agentNo"));
            dto.setRegistTime(jsonObject.getString("cusRegistTime"));
            dto.setAuthTime(jsonObject.getString("cusAuthTime"));
            dto.setActiveTime(jsonObject.getString("cusActiveTime"));
            dto.setUserName(jsonObject.getString("shopName"));
            dto.setRealName(jsonObject.getString("cusName"));
            dto.setPhone(jsonObject.getString("cusTel"));
            dto.setIdCard(jsonObject.getString("cusManId"));
            dto.setBankCardNo(jsonObject.getString("cusCardNo"));
            dto.setTerminalSn(jsonObject.getString("possNo"));
            dto.setUnionpayMerchantNo(jsonObject.getString("cusNo"));
            dto.setChannelId(ChannelIdEnums.YRB_YS_EPOS.getCode());
            dto.setPushWay(YsPaySaveMerchantDTO.PUSH_WAY_MERCHANT);
            return merchantYxyApiService.saveMerchant(dto);
        } else {
            Merchant21 merchant21Update=new Merchant21();
            merchant21Update.setMerchantId(merchant21.getMerchantId());
            merchant21Update.setRealName(jsonObject.getString("cusName"));
            merchant21Update.setIdCard(jsonObject.getString("cusManId"));
            merchant21Update.setPhone(jsonObject.getString("cusTel"));
            merchant21Update.setBankCard(jsonObject.getString("cusCardNo"));
            merchant21Mapper.updateByPrimaryKeySelective(merchant21Update);
            return Result.builder().success();
        }
    }

    /**
     * 机具绑定通知
     *
     * @param jsonObject
     * @return
     */
    @Override
    public Result bindPosNotify(JSONObject jsonObject) {

        log.info("易生机具绑定通知");

        if (commonService.repeatSubmit("callbackYisheng-bindPosNotify:" + jsonObject.getString("cusNo"))) {
            log.info("重复推送跳过:{}", jsonObject.toJSONString());
            return Result.builder().fail(BizCodeMessages.VALIDATOR_REPEAT_SUBMIT,"重复请求");
        }

        String bindResult = jsonObject.getString("result");
        if (Objects.nonNull(bindResult) && StringUtils.equals(bindResult, "00")) {

            String merchantNo = jsonObject.getString("shopNo");
            String terminalSn = jsonObject.getString("possNo");
            String bindTime = jsonObject.getString("bindTime");

            Terminal21 terminal21 = rpcYxyTerminalService.getTerminalBySn(terminalSn);
            if (Objects.isNull(terminal21)) {
                log.error("易生交易推送,机具不存在.");
                return Result.builder().fail();
            }

            Merchant21 merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(merchantNo);
            if (Objects.isNull(merchant21)) {
                log.info("易生交易推送,商户不存在插入");

                Map<String, String> payParams = payTypeApiService.getPayParams(PayTypeEnum.YI_SHENG, PayFromEnum.merchant);
                SaveMerchantDTO dto = new SaveMerchantDTO();
                dto.setMerchantNo(merchantNo);
                dto.setUserName(jsonObject.getString("shopName"));
                dto.setAgentNo(payParams.get("agentNo"));
                dto.setRegistTime(jsonObject.getString("bindTime"));
                dto.setAuthTime(jsonObject.getString("bindTime"));
                dto.setActiveTime(jsonObject.getString("bindTime"));
                dto.setTerminalSn(terminalSn);
                dto.setUnionpayMerchantNo(jsonObject.getString("cusNo"));
                dto.setChannelId(ChannelIdEnums.YRB_YS_EPOS.getCode());
                dto.setPushWay(YsPaySaveMerchantDTO.PUSH_WAY_MERCHANT);
                merchantYxyApiService.saveMerchant(dto);
                merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(merchantNo);
            }

            String bindUserBaseId = terminal21.getBindUserBaseId();
            if (StringUtils.isNotEmpty(bindUserBaseId)) {
                if (StringUtils.equals(merchant21.getUserBaseId(), bindUserBaseId)) {
                    log.info("机具已绑定，terminalSn={}, merchantNo={}", terminalSn, merchantNo);
                    return Result.builder().success();
                } else {
                    log.info("机具已绑定，需要换绑，terminalSn={}, merchantNo={}", terminalSn, merchantNo);
                }
            }

            return yxyTradeService.bindAndCreateReward(merchantNo, terminalSn, bindTime, merchant21.getUserBaseId(), terminal21.getChannelId());
        }

        return Result.builder().success();
    }

    /**
     * 交易通知
     *
     * @param jsonObject
     * @return
     */
    @Override
    public Result transactionNotify(JSONObject jsonObject) {
        log.info("易生交易通知");
        if (commonService.repeatSubmit("callbackYisheng-transactionNotify:" + jsonObject.getString("transNo"))) {
            log.info("重复推送跳过:{}", jsonObject.toJSONString());
            return Result.builder().fail(BizCodeMessages.VALIDATOR_REPEAT_SUBMIT,"重复请求");
        }

        YsTradeDTO ysTradeDTO = jsonObject.toJavaObject(YsTradeDTO.class);

        Merchant21 merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(ysTradeDTO.getShopNo());

        if (Objects.isNull(merchant21)) {
            log.error("拉卡拉交易推送,商户不存在.");
            return Result.builder().fail();
        }

        Terminal21 terminal21 = rpcYxyTerminalService.getTerminalBySn(ysTradeDTO.getPossNo());
        if (Objects.isNull(terminal21)) {
            log.error("易生格式化交易推送,机具号不存在，{}", jsonObject.toJSONString());
            return Result.builder().fail();
        }

        if (StringUtils.isBlank(terminal21.getBindUserBaseId())) {
            log.info("商终未绑定，调用绑机接口");
            Result bindResult = yxyTradeService.bindAndCreateReward(ysTradeDTO.getShopNo(), terminal21.getTerminalSn(),
                    ysTradeDTO.getPayDateTime(), merchant21.getUserBaseId(), terminal21.getChannelId());
            if (bindResult.isFail()) {
                log.error("拉卡拉交易推送,商户不存在，调用Rpc接口绑机失败");
                return Result.builder().fail();
            }
            // 商终绑定后，再次查询商户信息
            merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(ysTradeDTO.getShopNo());
        }

        // 格式化为 payTransaction
        PayTransaction payTransaction = payTransactionFormat(ysTradeDTO, merchant21);

        if (Objects.nonNull(payTransaction)) {
            // 保存交易
            return dealTrade(payTransaction);
        }
        return Result.builder().success();
    }

    /**
     * 商户费率变更通知
     *
     * @param jsonObject
     * @return
     */
    @Override
    public Result merchantRateNotify(JSONObject jsonObject) {
        log.info("易生商户费率变更通知");
        if (commonService.repeatSubmit("callbackYisheng-merchantRateNotify:" + jsonObject.getString("shopNo"))) {
            log.info("重复推送跳过:{}", jsonObject.toJSONString());
            return Result.builder().fail(BizCodeMessages.VALIDATOR_REPEAT_SUBMIT,"重复请求");
        }

        String bindResult = jsonObject.getString("result");
        if (Objects.nonNull(bindResult) && StringUtils.equals(bindResult, "00")) {
            Merchant21 merchant = merchantYxyApiService.getMerchant21ByMerchantNo(jsonObject.getString("shopNo"));
            if (Objects.isNull(merchant)) {
                log.error("易生商户费率变更通知,商户不存在.");
                return Result.builder().fail();
            }
            //刷卡费率
            if("shareConsumRate".equals(jsonObject.getString("updateKey"))){
                Merchant21 merchantUpdate=new Merchant21();
                merchantUpdate.setMerchantId(merchant.getMerchantId());
                merchantUpdate.setRateCredit(jsonObject.getBigDecimal("newRate").multiply(new BigDecimal("100")).intValue());
                merchant21Mapper.updateByPrimaryKeySelective(merchantUpdate);
                return Result.builder().success();
            }
        }

        return Result.builder().fail();
    }



    /**
     * 调用绑机接口
     * @param merchantNo
     * @param sn
     * @param bindTime
     * @return
     */
    private Terminal callbackBind(String merchantNo, String sn, String bindTime) {
        // 调用绑机接口
        RpcYxyCallbackBindDTO dto = new RpcYxyCallbackBindDTO();
        dto.setMerchantNo(merchantNo);
        dto.setMerchantBindTime(LocalDateUtils.stringToLocalDateTime(bindTime));
        dto.setSn(sn);

        log.info("rpc调用terminal绑定机具");
        Result<Terminal> terminalResult = rpcYxyTerminalService.callbackBind(dto);
        if (Objects.isNull(terminalResult) || terminalResult.isFail()) {
            log.error("调用绑机接口处理失败，{}", sn);
            return null;
        }
        return terminalResult.getData();
    }

    /**
     * 生成交易对象
     * @param ysTradeDTO
     * @return
     */
    public PayTransaction payTransactionFormat(YsTradeDTO ysTradeDTO, Merchant21 merchant21) {
        log.info("易生格式化交易推送入参:{}", JSONObject.toJSONString(ysTradeDTO));
        PayTransaction payTransaction = new PayTransaction();

        payTransaction.setMerchantId(merchant21.getMerchantId());
        payTransaction.setMerchantNo(ysTradeDTO.getShopNo());

        payTransaction.setUserBaseId(merchant21.getUserBaseId());
        payTransaction.setMerchantName(merchant21.getMerchantName());
        payTransaction.setOrderNo(ysTradeDTO.getTransNo());
        payTransaction.setTransactionNo(ysTradeDTO.getTransNo());
        payTransaction.setSysRef(ysTradeDTO.getTransNo());
        payTransaction.setTransactionAmount(ysTradeDTO.getPayMoney());
        payTransaction.setTransactionFee(ysTradeDTO.getPayFee());

        payTransaction.setCardFlag(formatCardFlag(ysTradeDTO.getCardType(), ysTradeDTO.getOrgTradeType()));

        payTransaction.setTerminalId(ysTradeDTO.getPossNo());
        payTransaction.setSn(ysTradeDTO.getPossNo());
        payTransaction.setTransactionCardNo(ysTradeDTO.getCardNo());
        payTransaction.setTransactionCardType(formatCardFlag(ysTradeDTO.getCardType(), ysTradeDTO.getOrgTradeType()));
        payTransaction.setStatus(formatTradeStatus(ysTradeDTO.getResult()));
        payTransaction.setRate(merchant21.getRateCredit());
        LocalDateTime transTime = LocalDateTime.now();
        if (StringUtils.isNotBlank(ysTradeDTO.getPayDateTime())) {
            transTime = LocalDateUtils.stringToLocalDateTime(ysTradeDTO.getPayDateTime(), DateFormat.DATETIME_DEFAULT.getPartten());
        }

        payTransaction.setTransactionTime(transTime);
        payTransaction.setTransactionMonth(LocalDateUtils.localDateTimeByFormat(transTime, DateFormat.DATE_MONTH.getPartten()));
        payTransaction.setTransactionDay(LocalDateUtils.localDateTimeByFormat(transTime, DateFormat.DATE_COMPACT.getPartten()));
        if (Objects.isNull(ysTradeDTO.getTxRate())) {
            payTransaction.setFeeAmt(BigDecimal.ZERO);
        } else {
            payTransaction.setFeeAmt(ysTradeDTO.getTxRate());
        }

        payTransaction.setWithdrawalStatus(PayTransactionEnum.WithdrawalStatusEnum.STATUS_40.getCode());

        payTransaction.setChannelId(merchant21.getChannelId());
        payTransaction.setPlatNo(PlatNoEnums.YXY.getCode());
        payTransaction.setIsDel(false);
        payTransaction.setSettlementBank(ysTradeDTO.getBankName());
        payTransaction.setTransactionNo(ysTradeDTO.getCardNo());
        payTransaction.setTransType(formatPledgeStatus(ysTradeDTO));
        // 流量扣费
        if (StringUtils.equals(LklTransTypeEnum.TYPE_012003.getTransType(),payTransaction.getTransType())) {
            payTransaction.setIccPayAmt(ysTradeDTO.getKfAmt());
        }
        //分润标识
        payTransaction.setProfitFlag(checkIsProfitFlag(payTransaction));

        return payTransaction;
    }

    /**
     * 保存易生的交易
     * @param payTransaction
     * @return
     */
    public Result dealTrade(PayTransaction payTransaction) {
        KLog.info("保存易生交易 入参:{}", payTransaction.toJSON());
        try {
            //存交易
            YxyTradeService yxyTradeService = SpringContextUtils.getBean(YxyTradeService.class);
            payTransaction = yxyTradeService.saveTrade(payTransaction);

            if (Objects.isNull(payTransaction) || !PayTransactionEnum.TransactionStatus.STATUS_10.isEquals(payTransaction.getStatus())) {
                return Result.builder().success();
            }

            Merchant21 merchant21 = merchantYxyApiService.getMerchant21ByMerchantNo(payTransaction.getMerchantNo());
            if (Objects.isNull(merchant21)) {
                log.error("保存易生交易, 商户为空，merchantNo={}", payTransaction.getMerchantNo());
                return Result.builder().fail(BizCodeMessages.MERCHANT_UN_EXISTED,
                        "保存易生交易, 商户为空，merchantNo={}", payTransaction.getMerchantNo());
            }

            //押金、流量卡类型，商户未返现才调激活返现
            if (StringUtils.equals(payTransaction.getTransType(), LklTransTypeEnum.TYPE_412001.getTransType())) {
                Merchant21 merchant21Up=new Merchant21();
                merchant21Up.setMerchantId(merchant21.getMerchantId());
                merchant21Up.setPledgeCashSuccessTime(payTransaction.getTransactionTime());
                merchant21Up.setPledgeCashOrderNo(payTransaction.getOrderNo());
                merchant21Up.setPledgeCashSerialNo(payTransaction.getOrderNo());
                merchant21Up.setPledgeCashStatus(MerchantEnum.PledgeCashStatusEnum.STATUS_200.getCode());
                merchant21Mapper.updateByPrimaryKeySelective(merchant21Up);
            }
            //调激活返现
            CheckActiveRewardYxyDTO dto = new CheckActiveRewardYxyDTO();
            dto.setChannelId(payTransaction.getChannelId());
            dto.setTerminalSn(payTransaction.getSn());
            dto.setPlatNo(PlatNoEnums.YXY.getCode());
            dto.setTradeAmount(payTransaction.getTransactionAmount());
            dto.setTradeTime(payTransaction.getTransactionTime());
            dto.setUserBaseId(payTransaction.getUserBaseId());
            dto.setOrderNo(payTransaction.getOrderNo());
            KLog.info("ys调用检查激活返现:{}", dto.toJSON());
            Result<Void> voidResult = merchantYxyRewardApiService.checkYxyReward(dto);
            KLog.info("ys检查激活返现结束:{}", voidResult.toString());
            // 计入分润
            payEposService.profitOpt(payTransaction);
            //私信调用
            payEposService.sendTransactionLetter(payTransaction);

        } catch (Exception e) {
            KLog.error("ys交易回调处理失败:{},入参:{}", e.getMessage(), payTransaction.toJSON(), e);
            return Result.builder().fail(BizCodeMessages.DB_WRITE_ERR, "ys交易回调处理失败");
        }
        return Result.builder().success();
    }

    /**
     * 格式化卡类型
     * @param cardType
     * @param payType
     * @return
     */
    private String formatCardFlag(String cardType, String payType) {

        if (StringUtils.equalsAny(payType, "SW02","W01")) {
            return PayTransactionEnum.CardFlagEnum.WECHAT.getCode();
        } else if (StringUtils.equalsAny(payType, "A01", "SA01")) {
            return PayTransactionEnum.CardFlagEnum.ALIPAY.getCode();
        } else if (StringUtils.equals(cardType, "C")) {
            return PayTransactionEnum.CardFlagEnum.CREDIT_CARD.getCode();
        } else if (StringUtils.equals(cardType, "D")) {
            return PayTransactionEnum.CardFlagEnum.BORROW_CARD.getCode();
        }else if (StringUtils.equalsAny(payType, "U01","SU01")) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode();
        }else if (StringUtils.equals(cardType, "V")) {
            return PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode();
        }
        return cardType + "_" + payType;

    }


    /**
     * 判断交易状态
     *
     * @param respCode 交易状态
     * @return
     */
    private Short formatTradeStatus(String respCode) {
        if (StringUtils.equals(respCode, "00")) {
            return PayTransactionEnum.TransactionStatus.STATUS_10.getCode();
        }

        return PayTransactionEnum.TransactionStatus.STATUS_20.getCode();
    }


    /**
     * 判断押金状态
     *
     * @param ysTradeDTO 交易实体
     * @return
     */
    private String formatPledgeStatus(YsTradeDTO ysTradeDTO) {
        if (StringUtils.equals(ysTradeDTO.getKfType(), "0")) {
            return LklTransTypeEnum.TYPE_012001.getTransType();
        } else if (StringUtils.equals(ysTradeDTO.getKfType(), "1")) {
            if (ysTradeDTO.getKfAmt().compareTo(BigDecimal.ZERO) > 0) {
                return LklTransTypeEnum.TYPE_412001.getTransType();
            } else {
                return LklTransTypeEnum.TYPE_012001.getTransType();
            }
        } else if (StringUtils.equals(ysTradeDTO.getKfType(), "2")) {
            return LklTransTypeEnum.TYPE_012003.getTransType();
        }
        log.error("formatPledgeStatus 未知类型：{}", ysTradeDTO.getKfType());
        return ysTradeDTO.getKfType();
    }

    //判断是否计入分润
    private boolean checkIsProfitFlag(PayTransaction payTransaction) {

        //贷记卡且非押金交易,非流量卡交易才计入分润
        if (StringUtils.equalsAny(payTransaction.getCardFlag(),
                PayTransactionEnum.CardFlagEnum.ALIPAY.getCode(),
                PayTransactionEnum.CardFlagEnum.WECHAT.getCode(),
                PayTransactionEnum.CardFlagEnum.CREDIT_CARD.getCode(),
                PayTransactionEnum.CardFlagEnum.UNIONCODE_CREDIT.getCode(),
                PayTransactionEnum.CardFlagEnum.UNIONCODE.getCode())) {
            return true;
        }

        return false;
    }
}